home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1999 Spring / macformat-077.iso / Shareware Plus / Development / SpriteWorld 2.2 Extra Demos / User Contributions / ButtonBreakOut ƒ / DataPersistence / DataPersistence.c next >
Encoding:
Text File  |  1999-01-11  |  10.2 KB  |  349 lines  |  [TEXT/CWIE]

  1. // DataPersistence.c
  2. // -------------------
  3. // v1.3
  4. // feedback: macdev@tnuctip.com
  5.  
  6. #include     "SWIncludes.h"
  7.  
  8. #define        OWNER
  9. #include     "DataPersistence.h"
  10. #undef        OWNER
  11.  
  12.  
  13.  
  14. // ©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©
  15. //                        THESE ROUTINES MAY BE CUSTOMIZED TO YOUR OWN DATA
  16. // ©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©
  17.  
  18. #pragma mark •————Customizable————
  19.  
  20. ///--------------------------------------------------------------------------------------
  21. // This do-nearly-nothing routine is here to allow easy customizing for whatever error 
  22. // management your app may need. 
  23. ///--------------------------------------------------------------------------------------
  24.  
  25. #include <stdio.h>
  26. #include <string.h>
  27.  
  28. void SWGErrorReportingStub (OSErr err)
  29. {
  30.     SInt16     i;
  31.  
  32.     if (err != noErr)
  33.     {
  34.         ///
  35.         // this should be replaced with whatever alert or action is appropriate for each app
  36.         ///
  37.  
  38.         for (i = 0; i < 3; i++)
  39.         {
  40.             SysBeep (1);            // even such a basic signal may be useful to reveal a problem
  41.             Delay (2, nil);
  42.         }
  43.     }
  44. }
  45.  
  46.  
  47.  
  48. // ©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©
  49. //                                    PUBLIC : called by your app
  50. // ©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©
  51.  
  52. #pragma mark •—————Public—————
  53.  
  54.  
  55. ///--------------------------------------------------------------------------------------
  56. // Open file; if it does not exist, switch to internal resource mode
  57. // After this call, excepting system errors, a resource file is guaranteed to be ready.
  58. ///--------------------------------------------------------------------------------------
  59.  
  60. OSErr SWGOpenPersistenceFile (void)
  61. {
  62.     OSErr        err                    = noErr;                            // default (if already open)
  63.     SInt16        vRef                = 0;
  64.     SInt32        dirID                = 0L;
  65.     FSSpec        fspec;
  66.  
  67.     if ((! gSWGPersistenceFileIsOpen) && (! gSWGPersistenceUsesAppFork))// if app's rez fork used, continue
  68.     {
  69.         err = FSMakeFSSpec (vRef, dirID, gPersistenceFileName, &fspec);  
  70.         if (err == fnfErr)
  71.         {
  72.             gSWGPersistenceUsesAppFork = true;                            // no separate file, will use app
  73.             gSWGPersistenceFileIsOpen = true;                            // functionally true
  74.             err = noErr;
  75.         }
  76.         else if (err == noErr)
  77.         {
  78.             gSWGPreviousResFile = CurResFile();
  79.             gSWGPersistenceResFile = FSpOpenResFile (&fspec, fsCurPerm);
  80.             err = ResError ();                                            // should be == noErr mostly
  81.             if (err == noErr)
  82.             {
  83.                 UseResFile (gSWGPersistenceResFile);   
  84.                 err = ResError ();                                        // will be == noErr
  85.                 gSWGPersistenceFileIsOpen = true;
  86.             }
  87.         }
  88.     }
  89.  
  90.     return err;
  91. }
  92.  
  93.  
  94. ///--------------------------------------------------------------------------------------
  95. // Close the file and flush disk
  96. ///--------------------------------------------------------------------------------------
  97.  
  98. void SWGClosePersistenceFile (void)
  99. {
  100.     if (gSWGPersistenceFileIsOpen && (! gSWGPersistenceUsesAppFork))
  101.     {
  102.         CloseResFile (gSWGPersistenceResFile);
  103.         gSWGPersistenceFileIsOpen = false;
  104.  
  105.         UseResFile (gSWGPreviousResFile);
  106.  
  107.         gSWGPreviousResFile = -1;
  108.         gSWGPersistenceResFile = -1;
  109.  
  110.         (void) FlushVol ("\p", 0);
  111.  
  112.         // restore the standard resource type
  113.         _SWGRestoreResourceType ();
  114.     }
  115. }
  116.  
  117.  
  118. ///--------------------------------------------------------------------------------------
  119. // If file is not open, we open it now, and return true (or false in case of error). 
  120. // If another routine has already opened the file, we do nothing and return false. 
  121. //
  122. // This lets the caller routine know if it has actually opened the file:
  123. // - If it has, it's also responsible for closing the file before returning (using 
  124. //         SWGClosePersistenceFile). 
  125. // - If it has not, the file was previously opened by another routine, and caller knows 
  126. //         it is _not_ responsible for closing it.
  127. //
  128. // This is useful for some special cases, illustrated in SpritePersistence.c.
  129. //
  130. // The newType argument optionally overrides DataPersistence's standard resource type.
  131. // If kNoNewType is passed, there will be no override.
  132. // Important note: when file is closed (SWGClosePersistenceFile), the type will be 
  133. // automatically restored to it's default value, so don't worry about it.
  134. ///--------------------------------------------------------------------------------------
  135.  
  136. Boolean SWGOpenPersistenceFileConditionally (OSType newType)
  137. {
  138.     if (! gSWGPersistenceFileIsOpen)
  139.     {
  140.         OSErr    err;
  141.  
  142.         err = SWGOpenPersistenceFile ();
  143.         if (err != noErr)
  144.             SWGErrorReportingStub (err);
  145.         else                                    // only if file opening succeeded
  146.         {
  147.             if (newType != kNoNewType)
  148.                 _SWGOverrideResourceType (newType);
  149.         }
  150.  
  151.         return (err == noErr);
  152.     }
  153.     return false;
  154. }
  155.  
  156.  
  157. ///--------------------------------------------------------------------------------------
  158. // Do the actual saving job for a record.
  159. // May return various system errors, including notOpenErr, or resource-related errors.
  160. ///--------------------------------------------------------------------------------------
  161.  
  162. OSErr SWGSaveRecord (Ptr recordP, Size recSize, SInt16 resourceID)
  163. {
  164.     OSErr                err                    = noErr;
  165.     Handle                h;
  166.     Boolean                createdResource        = false;
  167.     Boolean                readPhase            = true;
  168.  
  169.     if (! gSWGPersistenceFileIsOpen)
  170.         return notOpenErr;
  171.  
  172.     // Read the rez before writing; if not found, create it; if different size, adjust it
  173.  
  174.     while (readPhase)
  175.     {
  176.         h = GetResource (gSWGPersistenceResourceType, resourceID);
  177.         if (h == nil)
  178.         {
  179.             err = ResError ();
  180.             if ((err == noErr)                                // that's a strange one, but it does happen
  181.              || (err == resNotFound))                        // first time, must create it
  182.             {
  183.                 err = noErr;                                // is not an error for us
  184.                 h = NewHandleClear (recSize);
  185.                 if (h == nil)
  186.                     return memFullErr;
  187.  
  188.                 createdResource = true;
  189.             }
  190.             readPhase = false;                                // even if err
  191.         }
  192.         else if (recSize != GetHandleSize (h))
  193.         {
  194.             RemoveResource (h);                                // remove from file, will be recreated with new size
  195.                 // h is a now a regular handle
  196.             SetHandleSize (h, recSize);
  197.             err = MemError ();
  198.             createdResource = true;
  199.             readPhase = false;
  200.         }
  201.         else
  202.             readPhase = false;                                // normal case
  203.     }
  204.  
  205.     if (err == noErr)
  206.     {
  207.         err = PtrToXHand (recordP, h, recSize); 
  208.         if (err == noErr)
  209.         {
  210.             if (createdResource)
  211.                 AddResource (h, gSWGPersistenceResourceType, resourceID, "\p");
  212.             else
  213.                 ChangedResource (h);
  214.  
  215.             err = ResError ();                                    // normally == noErr
  216.             if (err == noErr)
  217.             {
  218.                 WriteResource (h);
  219.                 err = ResError ();
  220.             }
  221.         }
  222.  
  223.         SWGErrorReportingStub (err);
  224.  
  225.         ReleaseResource (h);
  226.     }
  227.     else                                                    // maybe handle allocated & not used ?
  228.     {
  229.         if (h != nil)                                        // wasn't used for a resource
  230.             DisposeHandle (h);
  231.     }
  232.  
  233.     return err;
  234. }
  235.  
  236.  
  237. ///--------------------------------------------------------------------------------------
  238. // This is provided for symmetry with SWGLoadString. Currently it's identical to SWGSaveRecord.
  239. ///--------------------------------------------------------------------------------------
  240.  
  241. // currently implemented as a macro:         #define SWGSaveString SWGSaveRecord
  242.  
  243.  
  244.  
  245. ///--------------------------------------------------------------------------------------
  246. // Do the actual loading job for a record.
  247. // May return various system errors, including notOpenErr, or resource-related errors.
  248. // Special errors kDataSizeBiggerError/kDataSizeSmallerError: resource didn't have the expected size. 
  249. // Will copy as many bytes as possible into recordP.
  250. // If resource not found, return the error code returned by system (resNotFound).
  251. ///--------------------------------------------------------------------------------------
  252.  
  253. OSErr SWGLoadRecord (Ptr recordP, Size recSize, SInt16 resourceID)
  254. {
  255.     OSErr                err                = noErr;
  256.     Handle                h;
  257.  
  258.     if (! gSWGPersistenceFileIsOpen)
  259.         return notOpenErr;
  260.  
  261.     h = GetResource (gSWGPersistenceResourceType, resourceID);
  262.     if (h == nil)
  263.     {
  264.         err = ResError ();
  265.         if (err == noErr)                                    // does happen
  266.             err = resNotFound;
  267.  
  268.             // init the record (no need to optimize this, it's an error situation)
  269.         while (recSize--)
  270.             *recordP++ = 0;
  271.     }
  272.     else
  273.     {
  274.         Size    hSize;
  275.  
  276.         hSize = GetHandleSize (h);
  277.         if (recSize != hSize)                                // most times will be ==
  278.         {
  279.             if (recSize > hSize)
  280.             {
  281.                 recSize = hSize;                            // don't access memory outside handle
  282.                 err = kDataSizeSmallerError;
  283.             }
  284.             else                                            // will not copy all the handle data
  285.                 err = kDataSizeBiggerError;
  286.         }
  287.  
  288.         BlockMove (*h, recordP, recSize);        // that's a memory-safe call, no handle locking necessary
  289.  
  290.         ReleaseResource (h);
  291.     }
  292.  
  293.     return err;
  294. }
  295.  
  296.  
  297. ///--------------------------------------------------------------------------------------
  298. // Do the actual loading job for a string. The difference with SWGLoadString is that a 
  299. // *smaller* size than expected is not considered an error.
  300. // May return various system errors, including notOpenErr, or resource-related errors.
  301. // Special error kDataSizeBiggerError: resource was *bigger* than the expected size. 
  302. // Will copy as many bytes as possible into recordP.
  303. // If resource not found, return the error code returned by system (resNotFound).
  304. ///--------------------------------------------------------------------------------------
  305.  
  306. OSErr SWGLoadString (Ptr stringP, Size maxStringSize, SInt16 resourceID)
  307. {
  308.     OSErr                err                = noErr;
  309.  
  310.     err = SWGLoadRecord (stringP, maxStringSize, resourceID);
  311.     if (err == kDataSizeSmallerError)                    // smaller data is normal for a string
  312.         err = noErr;
  313.  
  314.     return err;
  315. }
  316.  
  317.  
  318.  
  319. // ©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©
  320. //                                    PRIVATE : internal use only
  321. // ©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©
  322.  
  323. #pragma mark •—————Private—————
  324.  
  325.  
  326. ///--------------------------------------------------------------------------------------
  327. // Allows using other rez types than the standard one. SpritePersistence uses this so as 
  328. // to avoid collisions between it's resource numbers and yours.
  329. ///--------------------------------------------------------------------------------------
  330.  
  331. void _SWGOverrideResourceType (OSType newType)
  332. {
  333.     gSWGPersistenceResourceType = newType;
  334. }
  335.  
  336.  
  337. ///--------------------------------------------------------------------------------------
  338. // Restores the standard rez type.
  339. ///--------------------------------------------------------------------------------------
  340.  
  341. void _SWGRestoreResourceType (void)
  342. {
  343.     gSWGPersistenceResourceType = kDefaultPersistenceRezType;
  344. }
  345.  
  346.  
  347.  
  348. // end
  349.